'''
版权: Copyright (c) 2019 red

文件: root.py
创建日期: Friday January 4th 2019
作者: pao
说明:
1、分布式计算服务
'''
import datetime

STATUS_FREE = 'free'    # 状态：空闲
STATUS_CALCULATING = 'calculating'  # 状态：计算中
STATUS_ERROR = 'error'  # 状态：错误
STATUS_FINISHED = 'finished'  # 状态：结束


class DistributeCalculatingServer:
    # 分布式计算服务器
    def __init__(self):
        # 构造函数
        self.jobs = []

    def add_job(self, task_count, task_func_string, job_func_string, args):
        # 添加分布式计算工作
        # task_count: 要分解的任务数量
        # task_func_string: 用字符串表示的任务函数，此函数的原型是： func(job_index, args): return_value
        # job_func_string: 用字符串表示的计算工作汇总函数，此函数的原型是： func(task_results): return_value
        # args: 要传入函数的参数（可变）

        # 以下将工作分解成任务
        tasks = []
        for index in range(0, task_count):
            tasks.append({
                'index': index,  # 任务索引
                'status': STATUS_FREE,  # 任务状态
                'result': None,  # 任务结果
                'error': None,  # 错误
                'history': []  # 计算历史
            })

        new_job = {
            'index': len(self.jobs),
            'task_count': task_count,
            'task_func_string': task_func_string,
            'job_func_string': job_func_string,
            'args': args,
            'start_time': datetime.datetime.now(),
            'end_time': None,
            'tasks': tasks,
            'status': STATUS_CALCULATING,
            'result': None
        }
        self.jobs.append(new_job)
        return len(self.jobs) - 1

    def get_job(self, job_index):
        return self.jobs[job_index]

    def get_task(self, client_id):
        # 从任务列表中获取一个可用于计算的任务
        for job in self.jobs:
            for task in job.tasks:
                if task.status in (STATUS_FREE, STATUS_ERROR):
                    task.status = STATUS_CALCULATING
                    task.history.append({
                        'client_id': client_id,
                        'start_time': datetime.datetime.now(),
                        'status': None,
                        'end_time': None,
                        'error': None,
                        'result': None
                    })
                    return {
                        'job_index': job.index,
                        'task_index': task.index,
                        'func': job.task_func_string,
                        'args': job.args
                    }

    def __get_job_result(self, job):
        # 运行工作函数，如果所有的任务都完成了，则执行job_func_string
        for task in job.tasks:
            if task.status != STATUS_FINISHED:
                return

        task_results = []
        for task in job.tasks:
            task_results.append({
                'index': task.index,
                'result': task.result
            })
        job_result = 'job函数将返回值写到这个变量中'
        exec(job.job_func_string, None, {
            'args': task_results
        })
        job.result = job_result
        job.status = STATUS_FINISHED
        job.end_time = datetime.datetime.now(),

    def return_task_error(self, client_id, job_index, task_index, error):
        # 返回计算错误
        job = self.jobs[job_index]
        task = job.tasks[task_index]
        task.status = STATUS_ERROR
        task.error = error
        history = task.history[len(task.history)-1]
        history.end_time = datetime.datetime.now()
        history.error = error
        history.status = STATUS_ERROR

    def return_task_value(self, client_id, job_index, task_index, result_value):
        # 返回计算结果
        job = self.jobs[job_index]
        task = job.tasks[task_index]
        task.status = STATUS_FINISHED
        task.result = result_value
        history = task.history[len(task.history)-1]
        history.end_time = datetime.datetime.now()
        history.result = result_value
        history.status = STATUS_FINISHED
        self.__get_job_result(job)


task_func = '''
def task_sum_for_index(task_index):
    s = 0
    for i in range(task_index*1000, task_index*1000 + 1000):
        s = s + i
    return s
'''


job_func = '''
def job_sum(task_results):
    s = 0
    for result in task_results:
        s = s + result.result
    return s
'''
